package org.yunai.yfserver.enums;

import org.slf4j.Logger;
import org.yunai.yfserver.common.LoggerFactory;
import org.yunai.yfserver.util.Assert;

import java.util.ArrayList;
import java.util.List;

/**
 * 从0开始的可索引枚举接口定义<br />
 * 实现此接口的枚举各个元素的index可以不连续，但此接口的实现类多为稀疏数组结构，保持index连续可以节省空间
 * User: yunai
 * Date: 13-4-6
 * Time: 上午10:41
 * // TODO 以后拓展出个MappedEnum，专门用于Index跨度大的枚举
 */
public interface IndexedEnum {

    /**
     * 获取该枚举的索引值
     *
     * @return 返回>=0的索引值
     */
    int getIndex();

    public static class Util {

        private static final Logger LOGGER = LoggerFactory.getLogger(LoggerFactory.Logger.msg, Util.class);

        /**
         * 索引警戒上限，发现超过此值的索引可能存在较大的空间浪费
         */
        private static final int WARNING_MAX_INDEX = 1000;

        /**
         * 将枚举中的元素放到一个List中，每个元素在list中的下表即为他的index，如果有不连续的index，则空缺的index用null填充
         *
         * @param <E> 枚举类型
         * @param enums 枚举元素
         * @return 枚举元素数组
         */
        public static <E extends IndexedEnum> List<E> toIndexes(E[] enums) {
            int maxIndex = Integer.MIN_VALUE;
            int curIdx;
            // 找到最大index，此值+1就是结果list的size
            for (E enm : enums) {
                curIdx = enm.getIndex();
                // 索引不能为负
                Assert.isTrue(curIdx >= 0, String.format("枚举索引不能为负 index: %1$d type: %2$s ", curIdx, enums.getClass()
                        .getComponentType().getName()));
                if (curIdx > maxIndex) {
                    maxIndex = curIdx;
                }
            }
            if (maxIndex >= WARNING_MAX_INDEX) {
                LOGGER.warn("[toIndexes] [警告：枚举类{}中有索引超过{}的索引，如果有很多索引空缺，可能会造成空间浪费].",
                        enums.getClass().getComponentType().getName(), WARNING_MAX_INDEX);
            }
            List<E> instances = new ArrayList<>(maxIndex + 1);
            // 填充
            for (int i = 0, len = maxIndex + 1; i < len; i++) {
                instances.add(null);
            }
            for (E enm : enums) {
                curIdx = enm.getIndex();
                // 索引必须唯一
                Assert.isTrue(instances.get(curIdx) == null, "枚举中有重复的index type= "
                        + enums.getClass().getComponentType().getName());
                instances.set(curIdx, enm);
            }
            return instances;
        }

        /**
         * 根据枚举index返回枚举元素，index从0开始
         *
         * @param <E>    枚举类型
         * @param values 枚举元素数组
         * @param index  从0开始的index
         * @return 枚举元素
         */
        public static <E extends Enum<E>> E valueOf(List<E> values, int index) {
            E value;
            try {
                value = values.get(index);
            } catch (Exception e) {
                LOGGER.error("[valueOf] [从枚举中取元素时错误 type:{} index:{} error:{}].",
                        values.getClass().getComponentType().getName(), index, e.getMessage());
                return null;
            }
            return value;
        }
    }
}
